package com.wei.czz.framework.admin.manager;

import com.alibaba.fastjson2.JSON;
import com.wei.czz.common.constant.Constant;
import com.wei.czz.common.constant.EntityConstant;
import com.wei.czz.common.constant.RedisConstant;
import com.wei.czz.common.dto.admin.CheckDeptDto;
import com.wei.czz.common.dto.admin.DeptDto;
import com.wei.czz.common.dto.admin.dept.DeptDialogEnumDto;
import com.wei.czz.common.dto.admin.dept.DeptExcelDto;
import com.wei.czz.common.dto.admin.dept.DeptPageEnumDto;
import com.wei.czz.common.dto.common.NameValue;
import com.wei.czz.common.dto.common.UploadDto;
import com.wei.czz.common.easyexcel.listener.ObjectUploadListener;
import com.wei.czz.common.enums.CommonEnum;
import com.wei.czz.common.enums.ResultEnum;
import com.wei.czz.common.enums.common.exportTask.TaskTypeEnum;
import com.wei.czz.common.enums.common.exportTask.ExportStatusEnum;
import com.wei.czz.common.enums.common.importTask.ImportTaskTypeEnum;
import com.wei.czz.common.enums.admin.dept.BusinessTypeEnum;
import com.wei.czz.common.exception.CzzException;
import com.wei.czz.common.po.UserPo;
import com.wei.czz.common.tool.PageDto;
import com.wei.czz.common.utils.CacheKeyUtils;
import com.wei.czz.common.utils.CopyUtils;
import com.wei.czz.common.utils.ExcelUtils;
import com.wei.czz.common.utils.SecurityUtils;
import com.wei.czz.common.vo.admin.dept.DeptUploadVo;
import com.wei.czz.common.vo.admin.dept.DeptVo;
import com.wei.czz.common.vo.admin.dept.DeptFormVo;
import com.wei.czz.common.vo.common.ChoiceExportVo;
import com.wei.czz.framework.admin.entity.DeptEntity;
import com.wei.czz.framework.admin.entity.DeptUserEntity;
import com.wei.czz.framework.admin.helper.DeptHelper;
import com.wei.czz.framework.admin.helper.RoleHelper;
import com.wei.czz.framework.admin.helper.UserHelper;
import com.wei.czz.framework.admin.service.*;
import com.wei.czz.framework.common.entity.ExportTaskEntity;
import com.wei.czz.framework.common.helper.CacheHelper;
import com.wei.czz.framework.common.helper.ImportTaskHelper;
import com.wei.czz.framework.common.service.ExportTaskService;
import com.wei.czz.framework.common.service.SnowflakeService;
import com.wei.czz.framework.common.service.AsyncService;
import com.wei.czz.framework.common.service.MultiDictService;
import lombok.AllArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * Created by IntelliJ IDEA.
 *
 * @author wyw
 * date: 2023-12-06 18:34:41
 * className: DeptManager
 * version: 1.0
 * description:
 */
@Component
@AllArgsConstructor
public class DeptManager {

    private static final Logger log = LoggerFactory.getLogger(DeptManager.class);

    private final DeptService deptService;

    private final UserService userService;

    private final DeptUserService deptUserService;

    private final DeptRoleService deptRoleService;

    private final RoleService roleService;

    private final RoleMenuService roleMenuService;

    private final UserRoleService userRoleService;

    private final MultiDictService multiDictService;

    private final AsyncService asyncService;

    private final ExportTaskService exportTaskService;

    private final SnowflakeService snowflakeService;

    private final CacheHelper cacheHelper;

    private final UserHelper userHelper;

    private final RoleHelper roleHelper;

    private final DeptHelper deptHelper;

    private final ImportTaskHelper importTaskHelper;

    private final RedissonClient redissonClient;

    public void saveDept(DeptVo deptVo) {
        // 获取操作用户
        UserPo userPo = SecurityUtils.getUser();
        Date date = new Date();

        /*
            判断部门名称是否冲突
         */
        List<DeptEntity> deptList = deptService.findListByName(Collections.singletonList(deptVo.getName()));
        if (!CollectionUtils.isEmpty(deptList)) {
            throw new CzzException(ResultEnum.SERVICE_FAIL.getCode(), "部门名称冲突，请确认后再操作");
        }

        DeptEntity dept = new DeptEntity();
        dept.setId(null)
                .setParentId(deptVo.getParentId())
                .setParentPath(deptVo.getParentPath() + deptVo.getParentId() + Constant.SPLIT)
                .setName(deptVo.getName())
                .setBusinessType(deptVo.getBusinessType())
                .setSort(deptVo.getSort())
                .setStatus(CommonEnum.ZERO.getValue())
                .setDeleteStatus(CommonEnum.ZERO.getValue())
                .setUpdateTime(date)
                .setUpdateUser(StringUtils.EMPTY)
                .setUpdateUserId(CommonEnum.ZERO.getLongValue())
                .setCreateTime(date)
                .setCreateUser(userPo.getUsername())
                .setCreateUserId(userPo.getUserId());
        deptService.saveOrEdit(dept);
    }

    public UploadDto<DeptUploadVo> uploadDept(Boolean mustAll, ObjectUploadListener<DeptUploadVo> objectUploadListener) {
        // 获取操作用户
        UserPo userPo = SecurityUtils.getUser();
        Date date = new Date();

        ImportTaskTypeEnum importTaskTypeEnum = ImportTaskTypeEnum.DEPT;

        // 解析成功列表
        List<DeptUploadVo> successList = objectUploadListener.getSuccessList();
        // 解析成功映射
        Map<Integer, DeptUploadVo> successMap = objectUploadListener.getSuccessMap();
        // 解析失败列表
        List<DeptUploadVo> failList = objectUploadListener.getFailList();

        /*
            判断是否有可导入数据
         */
        if (successList.isEmpty()) {
            // 没有解析成功数据，直接返回
            return importTaskHelper.buildSyncUploadDto(importTaskTypeEnum, successList, failList, DeptUploadVo.class);
        }

        // 收集父级部门主键
        List<Long> deptIdList = CopyUtils.mapList(successList, DeptUploadVo::getParentNo);

        /*
            获取父级部门
         */
        List<DeptEntity> deptList = deptService.getList(deptIdList);
        // list 转 map
        Map<Long, DeptEntity> deptMap = CopyUtils.listToMap(deptList, DeptEntity::getId, Function.identity());

        List<DeptEntity> saveList = new ArrayList<>();

        Map<String, Integer> businessTypeNameMap = BusinessTypeEnum.getNameMap();

        Iterator<DeptUploadVo> iterator = successList.iterator();
        while (iterator.hasNext()) {
            DeptUploadVo deptUploadVo = iterator.next();

            // 获取业务类型
            Integer businessType = businessTypeNameMap.get(deptUploadVo.getBusinessTypeName());
            if (Objects.isNull(businessType)) {
                log.info("业务类型不存在。serial={} businessTypeName={}", deptUploadVo.getSerial(),
                        deptUploadVo.getBusinessTypeName());
                deptUploadVo.setErrorMessage("业务类型不存在");
                failList.add(deptUploadVo);
                iterator.remove();
                continue;
            }

            // 从数据库存储的部门中获取父级部门
            DeptEntity parentDept = deptMap.get(deptUploadVo.getParentNo());

            /*
                不是以下这三种情况，则判定该条数据错误
                1、父级部门不是0
                2、父级部门不是数据库已有的部门
                3、父级部门不是同一批上传的部门（需父级部门在正在遍历部门的前面）
             */
            if (!CommonEnum.ZERO.getLongValue().equals(deptUploadVo.getParentNo()) && Objects.isNull(parentDept)
                    && !successMap.containsKey(deptUploadVo.getParentNo().intValue())) {
                log.info("父级部门不存在。serial={} parentNo={}", deptUploadVo.getSerial(),
                        deptUploadVo.getParentNo());
                deptUploadVo.setErrorMessage("父级部门不存在");
                failList.add(deptUploadVo);
                iterator.remove();
                continue;
            }

            Long parentId;
            String parentPath;
            if (CommonEnum.ZERO.getLongValue().equals(deptUploadVo.getParentNo())) {
                parentId = CommonEnum.ZERO.getLongValue();
                parentPath = CommonEnum.ZERO.getValue() + Constant.SPLIT;

            } else if (Objects.nonNull(parentDept)) {
                parentId = parentDept.getId();
                parentPath = parentDept.getParentPath() + parentDept.getId() + Constant.SPLIT;

            } else {
                log.info("父级部门找不到。serial={} parentNo={}", deptUploadVo.getSerial(),
                        deptUploadVo.getParentNo());
                deptUploadVo.setErrorMessage("父级部门找不到");
                failList.add(deptUploadVo);
                iterator.remove();
                continue;
            }

            DeptEntity dept = new DeptEntity();
            dept.setId(snowflakeService.get())
                    .setParentId(parentId)
                    .setParentPath(parentPath)
                    .setName(deptUploadVo.getName())
                    .setBusinessType(businessType)
                    .setSort(deptUploadVo.getSort())
                    .setStatus(CommonEnum.ZERO.getValue())
                    .setDeleteStatus(CommonEnum.ZERO.getValue())
                    .setUpdateTime(date)
                    .setUpdateUser(StringUtils.EMPTY)
                    .setUpdateUserId(CommonEnum.ZERO.getLongValue())
                    .setCreateTime(date)
                    .setCreateUser(userPo.getUsername())
                    .setCreateUserId(userPo.getUserId());
            // 记录
            saveList.add(dept);
            // 增加新映射，方便下面使用
            deptMap.put(deptUploadVo.getSerial().longValue(), dept);
        }

        /*
            生成导入记录
         */
        UploadDto<DeptUploadVo> uploadDto = importTaskHelper.buildSyncUploadDto(importTaskTypeEnum, successList,
                failList, DeptUploadVo.class);

        if (saveList.isEmpty()) {
            log.info("映射成功数据为空");
            return uploadDto;
        }
        if (mustAll && !failList.isEmpty()) {
            log.info("存在解析错误数据，不保存解析成功数据");
            return uploadDto;
        }

        /*
            保存部门
         */
        deptService.batchSave(saveList);

        return uploadDto;
    }

    public PageDto<DeptDto> getPageDeptList(DeptFormVo deptFormVo) {
         // 获取请求用户主键
        Long optUserId = SecurityUtils.getUserId();

        /*
             缓存请求参数
         */
        String cacheKey = CacheKeyUtils.getParamCacheKey(EntityConstant.DEPT);
        cacheHelper.cache(cacheKey, deptFormVo);

        // TODO 后续可以做结果缓存

        /*
            请求模式【true-树形分页 false-全量分页】
         */
        boolean requestMode = StringUtils.isBlank(deptFormVo.getWord());

        List<Long> idList;
        // 判断请求用户是否超级管理员
        boolean superManager = userHelper.isSuperManager();
        if (superManager) {
            Long id = Optional.ofNullable(deptFormVo.getParentId()).orElse(CommonEnum.ZERO.getLongValue());
            idList = Collections.singletonList(id);

        } else {
            // 获取用户管理的部门主键
            idList = deptHelper.getManageDeptIdList(optUserId);
            log.info("用户直接管理部门主键。idList={}", idList);
            if (idList.isEmpty()) {
                throw new CzzException(ResultEnum.EMPTY.getCode(), "您没有可以管理的部门，请确认");
            }
            if (Objects.nonNull(deptFormVo.getParentId())) {
                if (!idList.contains(deptFormVo.getParentId())) {
                    log.info("没有查询该部门的权限");
                    throw new CzzException(ResultEnum.AUTH_FAIL);
                }
                idList = Collections.singletonList(deptFormVo.getParentId());
            }
        }

        /*
           分页获取部门
         */
        PageDto<DeptEntity> pageDto = deptService.getPageList(requestMode, idList, deptFormVo);
        if (pageDto.isEmpty()) {
            return pageDto.rebuild();
        }

        List<DeptEntity> deptList = pageDto.getList();

        if (!requestMode) {
            // 不是树形分页查询，直接进行数据封装并返回
            BiConsumer<DeptEntity, DeptDto> biConsumer = (dept, deptDto) -> {
                deptDto.setBusinessTypeName(BusinessTypeEnum.getName(dept.getBusinessType()))
                        .setStatusName(CommonEnum.getStatusName(dept.getStatus()))
                        .setDisabled(CommonEnum.ONE.getValue().equals(dept.getStatus()));
            };
            // 列表映射
            List<DeptDto> list = CopyUtils.mapList(deptList, DeptDto.class, biConsumer);
            // 封装返回
            return pageDto.rebuild(list);
        }

        /*
            部门树构造
         */
//        if (Objects.nonNull(deptFormVo.getParentId())) {
//            // 如果父级主键参数不为空，则此操作不需要管用户是否超级管理员
//            superManager = false;
//
//            // 更新主键列表，方便下面构造部门结构树
//            idList = deptList.stream().filter(dept -> dept.getParentId().equals(deptFormVo.getParentId()))
//                    .map(DeptEntity::getId)
//                    .collect(Collectors.toList());
//        }

        Consumer<DeptDto> consumer = deptDto -> {
            deptDto.setBusinessTypeName(BusinessTypeEnum.getName(deptDto.getBusinessType()))
                    .setStatusName(CommonEnum.getStatusName(deptDto.getStatus()))
                    .setDisabled(CommonEnum.ONE.getValue().equals(deptDto.getStatus()))
                    .setDataKey(snowflakeService.find());
        };
        List<DeptDto> deptDtoList = this.buildDeptTree(superManager, deptList, consumer,
                CopyUtils.mapSet(idList, Objects::toString));
        // 一级列表重新排序
        deptDtoList.sort(DeptDto::compareTo);

        // 封装返回
        return pageDto.rebuild(deptDtoList);
    }

    public DeptPageEnumDto getDeptPageParam() {
        // 获取请求用户主键
        Long optUserId = SecurityUtils.getUserId();

        // 判断请求用户是否超级管理员
        boolean superManager = userHelper.isSuperManager();

        List<DeptEntity> deptList;
        if (superManager) {
            // 超级管理员
            deptList = deptService.findDirectChildrenList(CommonEnum.ZERO.getLongValue());
        } else {
            // 不是超级管理员

            // 获取用户管理的部门主键
            List<Long> deptIdList = deptHelper.getManageDeptIdList(optUserId);
            if (deptIdList.isEmpty()) {
                throw new CzzException(ResultEnum.EMPTY.getCode(), "您没有可以管理的部门，请确认");
            }

            /*
                获取部门
             */
            deptList = deptService.findList(deptIdList);
        }

        List<NameValue<String>> _deptList = CopyUtils.mapList(deptList,
                dept -> new NameValue<>(dept.getName(), dept.getId().toString()));

        /*
            获取部门表单对象
         */
        String cacheKey = CacheKeyUtils.getParamCacheKey(EntityConstant.DEPT);
        DeptFormVo deptFormVo = cacheHelper.get(cacheKey, DeptFormVo.class);

        DeptPageEnumDto deptPageEnumDto = new DeptPageEnumDto();
        deptPageEnumDto.setDeptList(_deptList)
                .setBusinessTypeList(BusinessTypeEnum.getList())
                .setStatusList(CommonEnum.getStatusList())
                .setDeptVo(deptFormVo);
        return deptPageEnumDto;
    }

    public DeptDialogEnumDto getDialogEnum(Long parentId, Long deptId) {

        /*
            获取下一个排序等级
         */
        Integer nextSort = null;
        if (Objects.nonNull(parentId)) {
            nextSort = deptService.getNextSort(parentId);
        }

        /*
            获取部门树
         */
        DeptDto deptDto = this.getDeptTree(deptId);

        DeptDialogEnumDto enumDto = new DeptDialogEnumDto();
        enumDto.setNextSort(nextSort)
                .setDept(deptDto)
                .setBusinessTypeList(BusinessTypeEnum.getList());
        return enumDto;
    }


    public DeptDto getDeptTree(Long id) {
        // 获取请求用户主键
        Long optUserId = SecurityUtils.getUserId();

        // 判断请求用户是否超级管理员
        boolean superManager = userHelper.isSuperManager();

        List<DeptEntity> deptList;
        List<Long> idList = new ArrayList<>();
        if (superManager) {
            // 超级管理员
            deptList = deptService.getDeptList();

        } else {
            // 不是超级管理员

            // 获取用户管理的部门主键
            idList = deptHelper.getManageDeptIdList(optUserId);
            if (idList.isEmpty()) {
                throw new CzzException(ResultEnum.REQUEST_FAIL.getCode(), "您没有可以管理的部门，请确认");
            }

            /*
                获取部门
             */
            deptList = deptService.findList(idList);
        }

        String disableId = Optional.ofNullable(id).map(Objects::toString).orElse(StringUtils.SPACE);
        Consumer<DeptDto> consumer = deptDto -> {
            if (CommonEnum.ONE.getValue().equals(deptDto.getStatus()) || deptDto.getId().equals(disableId)
                    || deptDto.getParentPath().contains(disableId)) {
                /*
                    以下情况，将该部门状态设置为禁用
                    1、部门状态为禁用
                    2、部门主键和参数deptId一致
                    3、父级部门路径包含参数deptId
                 */
                deptDto.setDisabled(Boolean.TRUE);
            }
            deptDto.setDataKey(snowflakeService.find());
        };

        /*
            部门树构造
         */
        List<DeptDto> deptDtoList = this.buildDeptTree(superManager, deptList, consumer,
                CopyUtils.mapSet(idList, Objects::toString));

        DeptDto result = new DeptDto();
        result.setId(CommonEnum.ZERO.getStringValue())
                .setParentPath(StringUtils.EMPTY)
                .setName("顶级部门")
                .setStatus(CommonEnum.ZERO.getValue())
                .setDisabled(Boolean.FALSE)
                .setDataKey(snowflakeService.find())
                .setChildren(new TreeSet<>(deptDtoList));
        return result;
    }

    public List<DeptDto> getChildrenDeptTree(Long id) {
        // 获取请求用户主键
        Long optUserId = SecurityUtils.getUserId();

        // 判断请求用户是否超级管理员
        boolean superManager = userHelper.isSuperManager();

        List<DeptEntity> deptList;
        List<Long> idList = new ArrayList<>();

        if (superManager) {
            // 超级管理员
            /*
                获取部门
             */
            DeptEntity dept = deptService.get(id);

            String deptPath = dept.getParentPath() + dept.getId() + Constant.SPLIT;

            /*
                获取子、子孙..部门
             */
            deptList = deptService.getChildrenList(deptPath);

        } else {
            // 不是超级管理员，则需要判断参数是否用户直接管理部门获取其子、子孙部门

            // 获取用户管理的部门主键
            idList = deptHelper.getManageDeptIdList(optUserId);
            if (idList.isEmpty()) {
                throw new CzzException(ResultEnum.REQUEST_FAIL.getCode(), "您没有可以管理的部门，请确认");
            }

            /*
                获取部门
             */
            deptList = deptService.findList(idList);
            // 判断用户是否用户部门权限
            String idValue = id.toString();
            deptList = deptList.stream()
                    .filter(dept -> dept.getParentId().equals(id) || dept.getParentPath().contains(idValue))
                    .collect(Collectors.toList());
            if (deptList.isEmpty()) {
                log.info("用户没有部门操作权限");
                throw new CzzException(ResultEnum.REQUEST_FAIL.getCode(), "您没有改部门权限，请确认");
            }
        }

        /*
            部门树构造
         */
        Consumer<DeptDto> consumer = deptDto -> {
            deptDto.setDisabled(CommonEnum.ONE.getValue().equals(deptDto.getStatus()))
                    .setDataKey(snowflakeService.find());
        };

        List<DeptDto> deptDtoList = this.buildDeptTree(superManager, deptList, consumer,
                CopyUtils.mapSet(idList, Objects::toString));
        // 列表重新排序
        deptDtoList.sort(DeptDto::compareTo);
        return deptDtoList;
    }

    public CheckDeptDto deleteDeptCheck(Long id) {
        /*
            查询子、子孙..部门主键
         */
        List<Long> deptIdList = deptService.getChildrenIdList(id);
        deptIdList.add(id);

        // 统计所有部门关联的用户数
        Long userNum = deptUserService.getDeptUserCount(deptIdList);

        CheckDeptDto checkDeptDto = new CheckDeptDto();
        checkDeptDto.setUserNum(userNum.intValue());
        return checkDeptDto;
    }

    public Integer getNextSort(Long deptId) {
        if (Objects.isNull(deptId)) {
            deptId = CommonEnum.ZERO.getLongValue();
        }
        return deptService.getNextSort(deptId);
    }

    public void deptChoiceExport(Long taskId, HttpServletResponse response) {
        // 获取请求用户
        UserPo userPo = SecurityUtils.getUser();
        Date start = new Date();

        /*
            获取导出任务
         */
        ExportTaskEntity exportTask = exportTaskService.get(taskId);
        if (!ExportStatusEnum.ACTIVITY.getValue().equals(exportTask.getStatus())) {
            log.info("任务状态不对：status={}", ExportStatusEnum.getName(exportTask.getStatus()));
            throw new CzzException(ResultEnum.REQUEST_FAIL.getCode(), "部门导出已经下载过，不可重复下载");
        }

        /*
            获取缓存参数
         */
        ChoiceExportVo choiceExportVo = JSON.parseObject(exportTask.getParams(), ChoiceExportVo.class);
        log.info("缓存参数：{}", choiceExportVo);

        /*
            获取部门
         */
        List<DeptEntity> deptList = deptService.getList(choiceExportVo.getIdList());
        if (deptList.isEmpty()) {
            log.info("参数关联部门数据不存在");
            throw new CzzException(ResultEnum.ILLEGAL_FAIL);
        }

        Map<Long, String> deptMap = new HashMap<>();
        List<Long> parentIdList = new ArrayList<>();

        for (DeptEntity dept : deptList) {
            deptMap.put(dept.getId(), dept.getName());

            if (!deptMap.containsKey(dept.getParentId())) {
                parentIdList.add(dept.getParentId());
            }
        }

        if (!parentIdList.isEmpty()) {
            List<DeptEntity> list = deptService.getList(parentIdList);
            for (DeptEntity dept : list) {
                deptMap.put(dept.getId(), dept.getName());
            }
        }
        // 业务类型枚举映射
        Map<Integer, String> businessTypeMap = BusinessTypeEnum.getMap();
        // 状态枚举映射
        Map<Integer, String> statusMap = CommonEnum.getStatusMap();

        // 序号
        AtomicInteger serial = new AtomicInteger(1);

        // 列表映射
        List<DeptExcelDto> deptExcelList = CopyUtils.mapList(deptList, dept -> {
            DeptExcelDto deptExcelDto = CopyUtils.map(dept, DeptExcelDto.class);
            deptExcelDto.setSerial(serial.getAndIncrement());
            deptExcelDto.setParentName(deptMap.getOrDefault(dept.getParentId(), StringUtils.EMPTY));
            deptExcelDto.setBusinessTypeName(businessTypeMap.getOrDefault(dept.getBusinessType(), StringUtils.EMPTY));
            deptExcelDto.setStatusName(statusMap.getOrDefault(dept.getStatus(), StringUtils.EMPTY));
            return deptExcelDto;
        });
        String fileName = TaskTypeEnum.DEPT_CHOICE_EXPORT.getName();

        ExportTaskEntity updateExportTask = new ExportTaskEntity();

        try {
            // 数据写入输出流中
            ExcelUtils.writeResponse(fileName, deptExcelList, DeptExcelDto.class, response);

            DeptExcelDto deptExcelDto = deptExcelList.get(0);
            updateExportTask.setFields(JSON.toJSONString(deptExcelDto.getExportFieldList()))
                    .setDataRow(deptExcelList.size())
                    .setStatus(ExportStatusEnum.SUCCESS.getValue());

        } catch (Exception e) {
            log.error("部门自选数据导出文件写入输出流异常。message={}", e.getMessage(), e);

            String errorMessage = TaskTypeEnum.DEPT_CHOICE_EXPORT.getName() + "执行失败";

            updateExportTask.setStatus(ExportStatusEnum.FAIL.getValue())
                    .setRemark(errorMessage);

            response.reset();
            response.setContentType("application/json");
            response.setCharacterEncoding("utf-8");
            try {
                response.getWriter().println(errorMessage);
            } catch (IOException ex) {
                log.error("异常结果返回输出失败。message={}", ex.getMessage());
            }
        } finally {
            asyncService.execute(() -> {
                Date date = new Date();

                updateExportTask.setTaskId(taskId)
                        .setStartTime(start)
                        .setEndTime(date)
                        .setUpdateTime(date)
                        .setUpdateUser(userPo.getUsername())
                        .setUpdateUserId(userPo.getUserId());
                // 更新
                exportTaskService.saveExportTask(updateExportTask);
            });
        }
    }

    @Transactional
    public void updateDept(DeptVo deptVo) {
        // 获取请求用户
        UserPo userPo = SecurityUtils.getUser();
        Date date = new Date();

        String lockKey = RedisConstant.LOCK + EntityConstant.DEPT + Constant.SPLIT + deptVo.getId();
        RLock lock = redissonClient.getLock(lockKey);
        boolean bool = lock.tryLock();
        log.info("部门修改，尝试加锁完成。lockKey={} bool={}", lockKey, bool);
        if (!bool) {
            throw new CzzException(ResultEnum.TRY_LOCK_FAIL);
        }

        try {
            /*
                获取部门
             */
            DeptEntity dept = deptService.get(deptVo.getId());

            boolean isUpdateParent = true;
            if (!dept.getParentId().equals(deptVo.getParentId())) {
                // 如果父级部门路径没有以父级部门主键作为结尾，则说明变更了父级部门
                deptVo.setParentPath(deptVo.getParentPath() + deptVo.getParentId() + Constant.SPLIT) ;

                isUpdateParent = false;
            }

            /*
                更新部门
             */
            DeptEntity updateDept = new DeptEntity();
            updateDept.setId(deptVo.getId())
                    .setParentId(deptVo.getParentId())
                    .setParentPath(deptVo.getParentPath())
                    .setName(deptVo.getName())
                    .setBusinessType(deptVo.getBusinessType())
                    .setSort(deptVo.getSort())
                    .setUpdateTime(date)
                    .setUpdateUser(userPo.getUsername())
                    .setUpdateUserId(userPo.getUserId());
            deptService.saveOrEdit(updateDept);

            if (isUpdateParent) {
                log.info("修改完成");
                return;
            }
            /*
                修改子部门的部门路径
             */
            String deptPath = dept.getParentPath() + dept.getId() + Constant.SPLIT;

            // 查询子部门
            List<DeptEntity> deptList = deptService.getChildrenList(deptPath);
            if (!deptList.isEmpty()) {
                List<DeptEntity> updateDeptList = new ArrayList<>();
                for (DeptEntity deptEntity : deptList) {
                    deptPath = deptEntity.getParentPath();
                    // 部门路径替换
                    deptPath = deptPath.replaceFirst(dept.getParentPath(), deptVo.getParentPath());

                    updateDept = new DeptEntity();
                    updateDept.setId(deptEntity.getId())
                            .setParentPath(deptPath)
                            .setUpdateTime(date)
                            .setUpdateUser(userPo.getUsername())
                            .setUpdateUserId(userPo.getUserId());
                    updateDeptList.add(updateDept);
                }
                // 批量更新部门
                deptService.batchUpdate(updateDeptList);
            }
        } finally {
            if (lock.isLocked() && lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }

    public void updateDeptStatus(Long id, Integer status) {
        // 获取请求用户
        UserPo userPo = SecurityUtils.getUser();
        Date date = new Date();

        /*
            更新部门
         */
        DeptEntity updateDept = new DeptEntity();
        updateDept.setId(id)
                .setStatus(status)
                .setUpdateTime(date)
                .setUpdateUser(userPo.getUsername())
                .setUpdateUserId(userPo.getUserId());
        deptService.saveOrEdit(updateDept);
    }

    @Transactional
    public void deleteDept(Long id) {
        /*
            获取子、子孙..部门主键列表
         */
        List<Long> deptIdList = deptService.getChildrenIdList(id);
        deptIdList.add(id);

        List<DeptUserEntity> deptUserList = deptUserService.findList(deptIdList, null);
        if (!deptUserList.isEmpty()) {
            log.info("删除部门及其子部门存在用户，无法删除。size={}", deptUserList.size());
            throw new CzzException("部门及其子部门存在用户，无法删除");
        }

        /*
            批量删除部门
         */
        deptService.delete(deptIdList);

        /*
            删除部门关联角色
         */
        deptRoleService.deleteDeptRole(null, deptIdList, null);

    }

    /**
     * 部门映射
     * @param dept 部门对象
     * @return 映射结果
     */
    private DeptDto mapDeptDto(DeptEntity dept, Map<Long, String> userNameMap) {
        DeptDto deptDto = new DeptDto();
        deptDto.setId(dept.getId().toString());
        deptDto.setParentId(dept.getParentId().toString());
        deptDto.setParentPath(dept.getParentPath());
        deptDto.setName(dept.getName());
        deptDto.setSort(dept.getSort());
        deptDto.setStatus(dept.getStatus());
        deptDto.setDisabled(CommonEnum.ONE.getValue().equals(dept.getStatus()));
        deptDto.setUpdateTime(dept.getUpdateTime());
        deptDto.setUpdateUser(userNameMap.get(dept.getUpdateUserId()));
        deptDto.setCreateTime(dept.getCreateTime());
        deptDto.setCreateUser(userNameMap.get(dept.getCreateUserId()));

        return deptDto;
    }

    /**
     * 构造部门树结构数据
     *
     * @param deptList    部门列表
     * @param userNameMap 用户名称映射
     * @return 部门树结构数据列表
     */
    private List<DeptDto> buildDeptTree(List<DeptEntity> deptList, Consumer<DeptDto> consumer,
                                        Map<Long, String> userNameMap) {
        List<DeptDto> lastOptDeptList = new ArrayList<>();
        Map<String, DeptDto> deptMap = new HashMap<>();
        for (DeptEntity dept : deptList) {
            // 映射
            DeptDto deptDto = this.mapDeptDto(dept, userNameMap);

            if (Objects.nonNull(consumer)) {
                /*
                    数据操作
                 */
                consumer.accept(deptDto);
            }

            deptMap.put(deptDto.getId(), deptDto);

            DeptDto parentDeptDto = deptMap.get(deptDto.getParentId());
            if (Objects.isNull(parentDeptDto)) {
                // 延后处理
                lastOptDeptList.add(deptDto);
                continue;
            }

            TreeSet<DeptDto> children = parentDeptDto.getChildren();
            if (Objects.isNull(children)) {
                children = new TreeSet<>();
                parentDeptDto.setChildren(children);
            }
            children.add(deptDto);
        }
        List<DeptDto> deptDtoList = new ArrayList<>();
        for (DeptDto deptDto : lastOptDeptList) {
            DeptDto parentDeptDto = deptMap.get(deptDto.getParentId());
            if (Objects.isNull(parentDeptDto)) {
                // 直接加入结果列表
                deptDtoList.add(deptDto);
                continue;
            }

            TreeSet<DeptDto> children = parentDeptDto.getChildren();
            if (Objects.isNull(children)) {
                children = new TreeSet<>();
                parentDeptDto.setChildren(children);
            }
            children.add(deptDto);
        }
        deptDtoList.sort(Comparator.comparing(DeptDto::getSort));

        return deptDtoList;
    }

    /**
     * 构造部门树结构
     * @param superManager 请求用户是否超级管理员【true-是 false-不是】
     * @param deptList     部门对象列表
     * @param consumer     部门后置操作表达式
     * @param manageIdSet  用户直接管理的部门主键集合
     * @return 部门树结构对象列表
     */
    private List<DeptDto> buildDeptTree(boolean superManager, List<DeptEntity> deptList, Consumer<DeptDto> consumer,
                                        Set<String> manageIdSet)  {
        Map<String, DeptDto> deptMap = new HashMap<>();
        List<DeptDto> lastOptDeptList = new ArrayList<>();
        List<DeptDto> deptDtoList = new ArrayList<>();

        for (DeptEntity dept : deptList) {
            // 映射
            DeptDto deptDto = CopyUtils.map(dept, DeptDto.class);
            if (deptMap.containsKey(deptDto.getId())) {
                log.info("部门数据重复，直接过滤。id={} name={}", deptDto.getId(), deptDto.getName());
                continue;
            }
            // 数据操作
            consumer.accept(deptDto);

            deptMap.put(deptDto.getId(), deptDto);

            DeptDto parentDeptDto = deptMap.get(deptDto.getParentId());
            if (Objects.isNull(parentDeptDto)) {
                // 延后处理
                lastOptDeptList.add(deptDto);
                continue;
            }
            TreeSet<DeptDto> children = parentDeptDto.getChildren();
            if (Objects.isNull(children)) {
                children = new TreeSet<>();
                parentDeptDto.setChildren(children);
            }
            children.add(deptDto);
        }
        for (DeptDto deptDto : lastOptDeptList) {
            DeptDto parentDeptDto = deptMap.get(deptDto.getParentId());
            if (Objects.isNull(parentDeptDto)) {
                log.info("父级部门不存在，部门直接放入一级部门下面。id={} name={} parentId={} keys={}", deptDto.getId(),
                        deptDto.getName(), deptDto.getParentId(), deptMap.keySet());
                // 一级部门
                deptDtoList.add(deptDto);
                // 用户管理部门主键减少
                manageIdSet.remove(deptDto.getId());
                continue;
            }
            TreeSet<DeptDto> children = parentDeptDto.getChildren();
            if (Objects.isNull(children)) {
                children = new TreeSet<>();
                parentDeptDto.setChildren(children);
            }
            children.add(deptDto);
        }

        if (!superManager) {
            /*
                不是超级管理员，需要将用户直接管理部门放入到一级部门列表中
             */
            log.info("部门映射，所有键：{} 用户管理部门：{}", deptMap.keySet(), manageIdSet);
            for (String id : manageIdSet) {
                DeptDto deptDto = deptMap.get(id);
                if (Objects.isNull(deptDto)) {
                    log.info("部门不存在，部门复制失败。id={}", id);
                    continue;
                }
                /*
                    此处在复制一份数据，主要为了出现更加复杂的情况
                    例如：
                                        a
                                        b
                                c               d
                            f       g
                    用户直接管理部门： a,b,c
                    则返回数据结构应该是：
                    1                  a
                                       b
                                c               d
                            f       g
                    ----------------------------------
                    2                  b
                                c               d
                            f       g
                    ----------------------------------
                    3                  c
                                   f       g
                    ----------------------------------
                 */
                // 克隆一份数据
                deptDto = this.copyDept(deptDto, consumer);
                // 放入一级部门列表
                deptDtoList.add(deptDto);
            }
        }
        return deptDtoList;
    }

    /**
     * 部门复制
     * @param deptDto  部门对象
     * @param consumer 部门后置操作表达式
     * @return 部门对象
     */
    private DeptDto copyDept(DeptDto deptDto, Consumer<DeptDto> consumer) {
        // 深拷贝复制
        deptDto = CopyUtils.map(deptDto, DeptDto.class);

        /*
            部门及其子、子孙部门序号变更
         */
        Deque<DeptDto> deque = new ArrayDeque<>();
        deque.add(deptDto);
        while (!deque.isEmpty()) {
            DeptDto _dept = deque.poll();
            // 数据操作
            consumer.accept(_dept);

            // 遍历子集合
            TreeSet<DeptDto> children = _dept.getChildren();
            if (!CollectionUtils.isEmpty(children)) {
                deque.addAll(children);
            }
        }

        return deptDto;
    }
}
